package com.googlecode.monitoria.server;

import javax.servlet.http.HttpSession;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.googlecode.monitoria.client.beans.User;
import com.googlecode.monitoria.client.beans.UserType;
import com.googlecode.monitoria.client.services.MonitoriaService;
import com.googlecode.monitoria.client.to.UserTO;
import com.googlecode.monitoria.server.command.AdministratorCommands;
import com.googlecode.monitoria.server.command.MonitoriaCommands;
import com.googlecode.monitoria.server.command.StudentCommands;
import com.googlecode.monitoria.server.persistence.dao.AbstractDAO;
import com.googlecode.monitoria.server.persistence.dao.AbstractDAO.DAOFactory;
import com.googlecode.monitoria.server.persistence.dao.AbstractDAO.UserDAO;
import com.googlecode.monitoria.server.persistence.util.BCrypt;

/**
 * System Facade.
 * @author Ricardo Araújo Santos - ricardo@lsd.ufcg.edu.br
 */
public class MonitoriaServiceImpl extends RemoteServiceServlet implements MonitoriaService{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * {@inheritDoc}
	 */
	public Boolean isFirstRun() {
		return DAOFactory.getUserDAO().findByID( "admin" ) == null;
	}
	
	/**
	 * {@inheritDoc}
	 * @throws Exception 
	 */
	public void registerAdmin( String password ) throws Exception {
		if(!isFirstRun()){
			throw new Exception("Blocked operation");
		}
		if(password == null || password.trim().isEmpty()){
			throw new IllegalArgumentException();
		}
		DAOFactory.getUserDAO().save( new User("admin", BCrypt.hashpw( password.trim(), BCrypt.gensalt() ), UserType.TEACHER) );
	}

	/**
	 * {@inheritDoc}
	 */
	public UserTO login(String name, String password) {
		if(name == null || password == null || password.isEmpty()){
			throw new IllegalArgumentException();
		}
		if ( name.isEmpty() ){
			return null;
		} else {
			AbstractDAO<User> userDAO = DAOFactory.getUserDAO();
			User user = userDAO.findByID( name );
			if(user == null || !BCrypt.checkpw( password, user.getPassword() )){
				return null;
			}
			getSession().setAttribute( MonitoriaConstants.SESSION_USER_ATT,  UserSessionManager.getInstance().openSession(user));
			return new UserTO(user);
		}
	}

	private HttpSession getSession() {
		return this.getThreadLocalRequest().getSession();
	}

	/**
	 * {@inheritDoc}
	 */
	public UserTO getLoggedUser() {
		User userForSession = getUserFromCurrentSession();
		return userForSession == null? null : new UserTO( userForSession );
	}

	/**
	 * @return
	 */
	private User getUserFromCurrentSession() {
		Integer att = (Integer) getSession().getAttribute(MonitoriaConstants.SESSION_USER_ATT);
		return UserSessionManager.getInstance().getUserForSession(att);
	}

	/**
	 * {@inheritDoc}
	 * @return 
	 */
	public boolean logout() {
		Integer att = (Integer) getSession().getAttribute(MonitoriaConstants.SESSION_USER_ATT);
		getSession().removeAttribute(MonitoriaConstants.SESSION_USER_ATT);
		return UserSessionManager.getInstance().closeSession(att) != null;
	}

	private MonitoriaCommands getCommands() throws Exception{
		User userFromCurrentSession = getUserFromCurrentSession();
		if(userFromCurrentSession == null){
			throw new Exception();
		}
		switch (userFromCurrentSession.getType()) {
		case TEACHER:
			return new AdministratorCommands();
		default:
			return new StudentCommands();
		}
	}
	
	@Override
	public UserTO createTeacher(String name, String password) throws Exception {
		return getCommands().createTeacher(name, password);
	}
}
